package com.huluobo.a2203kotlinjetpackdemo.coroutine

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import com.huluobo.a2203kotlinjetpackdemo.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.lang.Exception

/**
 *  协程
 *  ANR Application not response(应用程序无响应),一般来讲是在主线程进行了耗时操作,避免这种操作基本上都是通过创建子线程来实现
 *  在Android中哪些可以进行异步任务,Runnable(Thread),Handler,AsyncTask,RxJava
 *  每一个Application都是一个进程,每一个进程中都有很多线程,协程可以看做是线程中的线程,处理的也是同步或者异步任务
 *  协程是一种并发设计模式
 */

class CoroutineActivity : AppCompatActivity() {
    val job = Job()//工作对象

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_coroutine)
//        //创建一个在IO线程运行的协程
//        //GlobalScope 顶层协程,一般在项目中不会这么去用
//        val job = GlobalScope.launch(Dispatchers.IO) {
//            Log.i("TagA", "当前线程:${Thread.currentThread().name}")
//        }
//
//        //取消协程工作
//        job.cancel()
//        //开启一条主线程当中的协程
//        GlobalScope.launch(Dispatchers.Main) {
//            Log.i("TAgA", "当前线程:${Thread.currentThread().name}")
//        }

        CoroutineScope(job).launch {
//            val result = async {
//                try {
//                    //模拟耗时请求
//                    delay(3000)
//                    "运算结果:" + 3 / 0
//                } catch (e: Exception) {
//                    "结果异常"
//                }
//            }.await()
//            Log.i("TagA", result)

            val startTime = System.currentTimeMillis()
            val result = async {
                delay(2000)
                "操作成功"
            }

            val result2 = async {
                delay(1000)
                "获取成功"
            }
            Log.i("TagA", "执行结果:${result.await()} - ${result2.await()}")
            val endTime = System.currentTimeMillis()
            Log.i("TagA", "执行时间:" + (endTime - startTime))
            //出现执行3秒的过程,因为result执行完成之后,会直接执行result2,会造成线程阻塞,所以时间会相加
            //程序是按照上下顺序来执行的,当我在过程中调用await时,会造成当前线程阻塞,所以是同步执行,造成结果的时间会叠加
            //如果在结果中调用await,这是时异步执行,这样就不会造成时间叠加
        }

        //使用挂起函数
        CoroutineScope(job).launch {
            loadData()
        }

        CoroutineScope(job).launch {
            //Dispatchers.IO 常用于耗时操作,比如网络请求,文件读写等
            //Dispatchers.Main 表示程序在主线程中执行,所以在开启协程时,他的代码不一定是在子线程中执行,也可以进行切换
            //Dispatchers.Default 表示默认,协程交给系统处理,一般用于计算密集型
            val result = withContext(Dispatchers.IO) {
                delay(2000)
                "操作成功"
            }
            Log.i("TagA", "result:$result")
        }

        loadDataFromNet()
    }

    //系统并不知道一个方法是否会在协程中执行,所以需要加上suspend(挂起)来提示其他开发者(程序员),当方法需要放到协程中调用时,需要加上挂起声明
    private suspend fun loadData() {
        delay(2000)//delay,或者异步,或者等待,都是一个挂起函数,必须要放到协程作用域中才能使用
        Log.i("TagA", "-----loadData-----")
    }

    private fun loadDataFromNet() {
//        Thread {
//            //执行网络请求操作
//            runOnUiThread {
//                //切换到UI线程更新UI
//            }
//        }

        //RxJava ,是在一个方法中切换线程,SubOn,ObserverOn,请求过程发生在子线程,请求结果,发生在主线程

        CoroutineScope(job).launch(Dispatchers.Main) {
            val result = getResult()
            showUi(result)
        }
    }

    private fun showUi(result: String) {
        val tv = findViewById<TextView>(R.id.centerTv)
        tv.text = result
    }

    private suspend fun getResult() =
        withContext(Dispatchers.IO) {
            delay(2000)
            "获取网络成功"
        }

}